import { formatDate, getLunarDayName, getLunarLeapMonth, getLunarLeapMonthDays, getLunarMonthDays, getLunarMonthName, getDaysInMonth, isDate, clamp, solarToLunar, toDate, } from '../../utils';
import { defaultConfig } from '../config';
export const defaultDatetimePickerProps = defaultConfig.datetimePicker;
export const getMinDate = () => {
    return new Date(new Date().getFullYear() - 10, 0, 1, 0, 0, 0);
};
export const getMaxDate = () => {
    return new Date(new Date().getFullYear() + 10, 11, 31, 23, 59, 59);
};
export const strategies = {
    y: [0, 4, 0, 0, (d) => d.getFullYear(), (d, val) => d.setFullYear(val)],
    M: [1, 2, 1, 12, (d) => d.getMonth() + 1, (d, val) => d.setMonth(val - 1)],
    d: [2, 2, 1, 31, (d) => d.getDate(), (d, val) => d.setDate(val)],
    h: [3, 2, 0, 23, (d) => d.getHours(), (d, val) => d.setHours(val)],
    m: [4, 2, 0, 59, (d) => d.getMinutes(), (d, val) => d.setMinutes(val)],
    s: [5, 2, 0, 59, (d) => d.getSeconds(), (d, val) => d.setSeconds(val)],
};
export const letterArray = ['y', 'M', 'd', 'h', 'm', 's'];
function getSolarBoundaryValue(isMax, endDate, currentDate) {
    const currEvery = [endDate.getFullYear()];
    const minOrMaxIndex = isMax ? 3 : 2;
    let aside = true;
    let prevGetter = strategies.y[4];
    letterArray.slice(1).forEach((letter, index) => {
        const strategy = strategies[letter];
        let minOrMax = strategy[minOrMaxIndex];
        if (isMax && letter === 'd') {
            minOrMax = getDaysInMonth(currentDate.getFullYear(), currentDate.getMonth());
        }
        aside = aside && currEvery[index] === prevGetter(currentDate);
        currEvery[index + 1] = aside ? strategy[4](endDate) : minOrMax;
        prevGetter = strategy[4];
    });
    return currEvery;
}
function getLunarBoundaryValue(isMax, endDate, currentDate) {
    const lunarDate = solarToLunar(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDate());
    const lunarEndDate = solarToLunar(endDate.getFullYear(), endDate.getMonth() + 1, endDate.getDate());
    const currEvery = [lunarEndDate.year];
    const minOrMaxIndex = isMax ? 3 : 2;
    let aside = true;
    let prevGetter = strategies.y[4];
    letterArray.slice(1).forEach((letter, index) => {
        const prevValue = currEvery[index];
        const strategy = strategies[letter];
        const currGetter = strategy[4];
        let minOrMax = strategy[minOrMaxIndex];
        if (isMax && letter === 'd') {
            minOrMax =
                lunarDate.month < 0
                    ? getLunarLeapMonthDays(lunarDate.year)
                    : getLunarMonthDays(lunarDate.year, lunarDate.month);
        }
        let asideValue = 0;
        if (aside) {
            if (letter === 'M') {
                aside = lunarDate.year === prevValue;
                if (aside) {
                    asideValue = lunarEndDate.month;
                }
            }
            else if (letter === 'd') {
                aside = lunarDate.month === prevValue;
                if (aside) {
                    asideValue = lunarEndDate.day;
                }
            }
            else {
                aside = prevGetter(currentDate) === prevValue;
                if (aside) {
                    asideValue = currGetter(currentDate);
                }
            }
        }
        currEvery[index + 1] = aside ? asideValue : minOrMax;
        prevGetter = currGetter;
    });
    return currEvery;
}
export function getBoundaryValue(calendar, isMax, endDate, currentDate) {
    return calendar === 'solar'
        ? getSolarBoundaryValue(isMax, endDate, currentDate)
        : getLunarBoundaryValue(isMax, endDate, currentDate);
}
export function correctSolarDate(date, minDate, maxDate) {
    let minAside = true;
    let maxAside = true;
    let prevGetter = strategies.y[4];
    letterArray.slice(1).forEach((letter, index) => {
        const strategy = strategies[letter];
        let minValue = strategy[2];
        let maxValue = strategy[3];
        if (letter === 'd') {
            maxValue = getDaysInMonth(date[0], date[1] - 1);
        }
        const currGetter = strategy[4];
        if ((minAside = minAside && prevGetter(minDate) === date[index])) {
            minValue = currGetter(minDate);
        }
        if ((maxAside = maxAside && prevGetter(maxDate) === date[index])) {
            maxValue = currGetter(maxDate);
        }
        date[index + 1] = clamp(date[index + 1], minValue, maxValue);
        prevGetter = currGetter;
    });
}
export function correctLunarDate(date, minDate, maxDate) {
    const lunarMinDate = solarToLunar(minDate.getFullYear(), minDate.getMonth() + 1, minDate.getDate());
    const lunarMaxDate = solarToLunar(maxDate.getFullYear(), maxDate.getMonth() + 1, maxDate.getDate());
    const range = [
        {
            value: 0,
            edge: true,
            date: minDate,
            lunarDate: lunarMinDate,
        },
        {
            value: 0,
            edge: true,
            date: maxDate,
            lunarDate: lunarMaxDate,
        },
    ];
    let prevGetter = strategies.y[4];
    letterArray.slice(1).forEach((letter, index) => {
        const prevValue = date[index];
        const currIndex = index + 1;
        const currValue = date[currIndex];
        const strategy = strategies[letter];
        range[0].value = strategy[2];
        range[1].value = strategy[3];
        if (letter === 'd') {
            range[1].value =
                date[1] < 0
                    ? getLunarLeapMonthDays(date[0])
                    : getLunarMonthDays(date[0], date[1]);
        }
        let currGetter = strategy[4];
        range.forEach((point) => {
            if (point.edge) {
                if (letter === 'M') {
                    point.edge = point.lunarDate.year === prevValue;
                    if (point.edge) {
                        point.value = point.lunarDate.month;
                    }
                }
                else if (letter === 'd') {
                    point.edge = point.lunarDate.month === prevValue;
                    if (point.edge) {
                        point.value = point.lunarDate.day;
                    }
                }
                else {
                    point.edge = prevGetter(point.date) === prevValue;
                    if (point.edge) {
                        point.value = currGetter(point.date);
                    }
                }
            }
        });
        if (letter === 'M') {
            let min = range[0].value;
            let max = range[1].value;
            let value = currValue;
            if (min < 0) {
                min = Math.abs(min) + 0.5;
            }
            else if (max < 0) {
                max = Math.abs(max) + 0.5;
            }
            if (value < 0) {
                value = Math.abs(value) + 0.5;
            }
            value = clamp(value, min, max);
            date[currIndex] = value % 1 === 0.5 ? ~~value * -1 : value;
        }
        else {
            date[currIndex] = clamp(currValue, range[0].value, range[1].value);
        }
        if (letter === 'd') {
            currGetter = (date) => {
                return date === minDate ? lunarMinDate.day : lunarMaxDate.day;
            };
        }
        prevGetter = currGetter;
    });
}
export function correctDate(calendar, date, minDate, maxDate) {
    if (calendar === 'solar') {
        correctSolarDate(date, minDate, maxDate);
    }
    else {
        correctLunarDate(date, minDate, maxDate);
    }
}
export const getColumnData = (calendar, min, max, length, letter, currentDate, translate, filter, formatter) => {
    const lunarDate = solarToLunar(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDate());
    let column = Array(Math.abs(max) - Math.abs(min) + 1)
        .fill(0)
        .map((_, i) => ({
        value: i + Math.abs(min),
    }));
    if (calendar === 'lunar' && letter === 'M') {
        if (min < 0) {
            column[0].value = min;
        }
        else if (max < 0) {
            column.push({
                value: max,
            });
        }
        else {
            const leapMonth = getLunarLeapMonth(lunarDate.year);
            if (leapMonth > 0 && leapMonth > min && leapMonth < max) {
                column.splice(column.findIndex((item) => item.value === leapMonth) + 1, 0, {
                    value: -leapMonth,
                });
            }
        }
    }
    if (filter) {
        column = column.filter((option, i) => filter(letter, option.value, currentDate, i));
    }
    column.forEach((option) => {
        option.zerofill = String(option.value).padStart(length, '0');
        if (calendar === 'solar') {
            option.label = option.zerofill + translate(letter);
        }
        else {
            switch (letter) {
                case 'M':
                    option.label = getLunarMonthName(Math.abs(option.value), option.value < 0);
                    break;
                case 'd':
                    option.label = getLunarDayName(option.value);
                    break;
                default:
                    option.label = option.zerofill + translate(letter);
                    break;
            }
        }
    });
    if (formatter) {
        column.forEach((option, i) => {
            option.label = formatter(letter, option, currentDate, i) ?? option.label;
        });
    }
    return column;
};
export function getInitialValue(minDate, maxDate) {
    const value = new Date();
    return value.getTime() < minDate.getTime()
        ? new Date(minDate)
        : value.getTime() > maxDate.getTime()
            ? new Date(maxDate)
            : value;
}
export const normalizeRangeValue = (minDate, maxDate, value, valueFormat) => {
    const [start, end] = value || [];
    const startValue = start || getInitialValue(minDate, maxDate);
    const endValue = end || getInitialValue(toDate(startValue, valueFormat), maxDate);
    return [
        valueFormat && isDate(startValue)
            ? formatDate(startValue, valueFormat)
            : startValue,
        valueFormat && isDate(endValue)
            ? formatDate(endValue, valueFormat)
            : endValue,
    ];
};
